梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)
本教程将从 C++ 键值对(pair)和元组(tuple)的核心概念、特性入手,详细讲解两者的定义、初始化、访问方式及典型应用场景,帮助你掌握这两种轻量级复合数据类型的核心用法。
C++ 中的 std::pair 是定义在 <utility> 头文件中的轻量级复合数据类型,用于封装两个不同类型的元素(也可相同),形成“键-值”(key-value)映射关系,是 C++ 标准库中最基础的复合类型之一。
pair 的核心特点:
first(键),第二个为 second(值);pair<int, string>、pair<double, double>);first 优先,second 次之);map、unordered_map)的底层基础单元。C++ 中的 std::tuple 是定义在 <tuple> 头文件中的通用复合数据类型,是 pair 的“升级版”,用于封装任意数量、任意类型的元素,实现多维度数据的聚合。
tuple 的核心特点:
| 特点 | std::pair | std::tuple |
|---|---|---|
| 元素数量 | 固定2个 | 任意数量(0+) |
| 访问方式 | 通过 first/second 直接访问 |
通过 std::get<索引>() 模板函数访问 |
| 头文件 | <utility> | <tuple> |
| 适用场景 | 二元键值映射(如map元素、简单数据配对) | 多维度数据聚合(如多字段记录、多值返回) |
| 底层关系 | 可视为特殊的 tuple(tuple<T1, T2>) | 通用化的复合类型,包含 pair 的能力 |
使用 pair 前需包含头文件 #include <utility>(STL容器头文件通常会间接包含,可省略),支持多种初始化方式:
#include <iostream>
#include <utility> // pair核心头文件
#include <string>
using namespace std;
int main() {
// 默认构造:元素值为对应类型的默认值
pair<int, string> p1;
// 手动赋值
p1.first = 101; // 第一个元素(键)
p1.second = "张三"; // 第二个元素(值)
cout << "p1: " << p1.first << " - " << p1.second << endl;
return 0;
}
int main() {
// 直接传入两个元素初始化
pair<int, string> p2(102, "李四");
pair<double, bool> p3(98.5, true);
cout << "p2: " << p2.first << " - " << p2.second << endl;
cout << "p3: " << p3.first << " - " << boolalpha << p3.second << endl;
return 0;
}
int main() {
// make_pair自动推导元素类型,无需显式指定
auto p4 = make_pair(103, "王五");
auto p5 = make_pair(3.14, "圆周率");
cout << "p4: " << p4.first << " - " << p4.second << endl;
cout << "p5: " << p5.first << " - " << p5.second << endl;
return 0;
}
pair 的两个元素通过 first 和 second 直接访问,支持读写操作:
int main() {
pair<string, int> p = make_pair("苹果", 5);
// 读取成员
cout << "商品:" << p.first << ",价格:" << p.second << endl;
// 修改成员
p.second = 6; // 修改价格
cout << "修改后:" << p.first << ",价格:" << p.second << endl;
return 0;
}
STL 中的 map 容器底层以 pair 为存储单元,key 对应 pair.first,value 对应 pair.second:
#include <iostream>
#include <map> // map头文件
#include <string>
using namespace std;
int main() {
// map的每个元素都是pair<const key, value>
map<int, string> stuMap;
// 插入pair元素
stuMap.insert(pair<int, string>(101, "张三"));
stuMap.insert(make_pair(102, "李四"));
stuMap[103] = "王五"; // 简化赋值(底层仍为pair)
// 遍历map,访问pair元素
for (const auto& p : stuMap) {
cout << "学号:" << p.first << ",姓名:" << p.second << endl;
}
return 0;
}
利用 pair 实现函数返回两个不同类型的值:
#include <iostream>
#include <utility>
#include <string>
using namespace std;
// 返回学生的(姓名,成绩)
pair<string, float> getStudentInfo() {
return make_pair("赵六", 92.5);
}
int main() {
auto [name, score] = getStudentInfo(); // C++17结构化绑定(简化访问)
cout << "姓名:" << name << ",成绩:" << score << endl;
// 兼容低版本C++的写法
pair<string, float> info = getStudentInfo();
cout << "姓名:" << info.first << ",成绩:" << info.second << endl;
return 0;
}
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
int main() {
// 存储多个坐标点(x,y)
vector<pair<int, int>> points;
points.push_back(make_pair(1, 2));
points.push_back(make_pair(3, 4));
points.push_back(make_pair(5, 6));
// 遍历坐标
for (const auto& p : points) {
cout << "坐标(" << p.first << ", " << p.second << ")" << endl;
}
return 0;
}
使用 tuple 前需包含头文件 #include <tuple>,支持多种初始化方式:
#include <iostream>
#include <tuple> // tuple核心头文件
#include <string>
using namespace std;
int main() {
// 显式指定类型:tuple<类型1, 类型2, 类型3...>
tuple<int, string, float, bool> t1(101, "张三", 92.5, true);
cout << "学号:" << get<0>(t1) << endl; // 索引从0开始
cout << "姓名:" << get<1>(t1) << endl;
return 0;
}
int main() {
// make_tuple自动推导类型,简化写法
auto t2 = make_tuple(102, "李四", 88.0, false);
auto t3 = make_tuple("苹果", 5.99, 100); // 字符串、浮点数、整数
cout << "商品:" << get<0>(t3) << ",单价:" << get<1>(t3) << ",库存:" << get<2>(t3) << endl;
return 0;
}
int main() {
// 默认构造:元素为对应类型默认值
tuple<string, int, double> t4;
// 赋值
t4 = make_tuple("香蕉", 3, 2.99);
cout << "赋值后:" << get<0>(t4) << " - " << get<1>(t4) << " - " << get<2>(t4) << endl;
return 0;
}
索引必须是编译期常量(字面量或constexpr变量),支持读写操作:
int main() {
auto t = make_tuple("赵六", 17, 90.0, "男");
// 读取元素(索引从0开始)
cout << "姓名:" << get<0>(t) << endl;
cout << "年龄:" << get<1>(t) << endl;
cout << "成绩:" << get<2>(t) << endl;
cout << "性别:" << get<3>(t) << endl;
// 修改元素
get<2>(t) = 95.5;
cout << "修改后成绩:" << get<2>(t) << endl;
return 0;
}
int main() {
auto t = make_tuple("孙七", 18, 85.5, "女", 104);
// 结构化绑定:一次性解包所有元素
auto [name, age, score, gender, id] = t;
cout << "学号:" << id << ",姓名:" << name << ",年龄:" << age
<< ",成绩:" << score << ",性别:" << gender << endl;
return 0;
}
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
int main() {
auto t = make_tuple(1, "hello", 3.14);
// 获取元素数量(编译期常量)
constexpr size_t size = tuple_size<decltype(t)>::value;
cout << "tuple元素数量:" << size << endl; // 输出3
return 0;
}
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
int main() {
auto t1 = make_tuple(101, "张三");
auto t2 = make_tuple(92.5, "男");
// 拼接两个tuple
auto t3 = tuple_cat(t1, t2);
// t3包含4个元素:101, "张三", 92.5, "男"
cout << get<0>(t3) << " - " << get<1>(t3) << " - "
<< get<2>(t3) << " - " << get<3>(t3) << endl;
return 0;
}
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
int main() {
auto t1 = make_tuple(1, 2, 3);
auto t2 = make_tuple(1, 3, 2);
auto t3 = make_tuple(1, 2, 3);
cout << boolalpha;
cout << "t1 == t2: " << (t1 == t2) << endl; // false
cout << "t1 == t3: " << (t1 == t3) << endl; // true
cout << "t1 < t2: " << (t1 < t2) << endl; // true(按索引依次比较)
return 0;
}
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
// 返回学生的(学号、姓名、成绩、是否及格)
tuple<int, string, float, bool> getStudentDetail() {
int id = 105;
string name = "周八";
float score = 88.5;
bool pass = score >= 60;
return make_tuple(id, name, score, pass);
}
int main() {
// 结构化绑定解包
auto [id, name, score, pass] = getStudentDetail();
cout << "学号:" << id << endl;
cout << "姓名:" << name << endl;
cout << "成绩:" << score << endl;
cout << "是否及格:" << boolalpha << pass << endl;
return 0;
}
#include <iostream>
#include <tuple>
#include <vector>
#include <string>
using namespace std;
int main() {
// 存储商品信息:(名称、单价、库存、是否上架)
vector<tuple<string, double, int, boo>> goods;
goods.push_back(make_tuple("手机", 2999.99, 50, true));
goods.push_back(make_tuple("耳机", 199.9, 200, true));
goods.push_back(make_tuple("充电器", 49.9, 500, false));
// 遍历商品列表
for (const auto& g : goods) {
cout << "商品:" << get<0<(g)
<< ",单价:" << get<1<(g)
<< ",库存:" << get<2<(g)
<< ",是否上架:" << boolalpha << get<3>(g) << endl;
}
return 0;
}
#include <iostream>
#include <tuple>
#include <vector>
#include <string>
using namespace std;
int main() {
// tuple中嵌套pair,实现更复杂的复合数据
tuple<pair<int, string>, float, string> t(
make_pair(106, "吴九"),
90.0,
"高三(1)班"
);
// 访问嵌套的pair
cout << "学号:" << get<0>(t).first << endl;
cout << "姓名:" << get<0>(t).second << endl;
cout << "成绩:" << get<1>(t) << endl;
cout << "班级:" << get<2>(t) << endl;
return 0;
}
<utility>,tuple 需包含 <tuple>;STL容器头文件(如 <map>)会间接包含 <utility>,可省略显式引入;std::get<N>() 的索引 N 必须是编译期常量,不能是运行时变量(如循环变量);get 或手动解包;tuple<>),但无实际业务意义,通常用于模板兼容场景。first/second 访问,是 STL 容器(map)的基础;std::get<索引>() 或结构化绑定访问;本教程全面讲解了 C++ pair 和 tuple 的核心概念、初始化、访问方式及典型应用。掌握这两种轻量级复合类型,能大幅简化多数据聚合、多值返回等场景的代码实现,是 C++ 标准库使用的核心技能之一。